//
// Saru.Base.Math.matrix3.cs: 3 Dimensional matrices and operations
//
// Author:
//   Jan Van Sweevelt (vansweej@gmail.com)
//
// Copyright (C) 2007
// 

using System;

namespace Saru.Base.Math {

    public class Matrix3f {

	// Constructors

        // create identity matrix
	public Matrix3f() {
	    tuple = new float[9];
	    MakeIdentity();
	}

	// copy constructor
	public Matrix3f(Matrix3f M) {
	    tuple = new float[9];
	    tuple[0] = M.tuple[0];
	    tuple[1] = M.tuple[1];
	    tuple[2] = M.tuple[2];
	    tuple[3] = M.tuple[3];
	    tuple[4] = M.tuple[4];
	    tuple[5] = M.tuple[5];
	    tuple[6] = M.tuple[6];
	    tuple[7] = M.tuple[7];
	    tuple[8] = M.tuple[8];
	}

	// construct from floating points
	public Matrix3f(float M00, float M01, float M02, float M10, float M11, float M12, float M20, float M21, float M22) {
	    tuple = new float[9];
	    tuple[0] = M00;
	    tuple[1] = M01;
	    tuple[2] = M02;
	    tuple[3] = M10;
	    tuple[4] = M11;
	    tuple[5] = M12;
	    tuple[6] = M20;
	    tuple[7] = M21;
	    tuple[8] = M22;
	}

	// construct from vectors
	// colums means:
	// true: vectors are colums of the matrix
	// false: vectors are rows of the matrix
	public Matrix3f(Vector3f V1, Vector3f V2, Vector3f V3, bool colums) {
	    tuple = new float[9];
	    if(colums) {
		tuple[0] = V1.X;
		tuple[1] = V2.X;
		tuple[2] = V3.X;
		tuple[3] = V1.Y;
		tuple[4] = V2.Y;
		tuple[5] = V3.Y;
		tuple[6] = V1.Z;
		tuple[7] = V2.Z;
		tuple[8] = V3.Z;		
	    }
	    else {
		tuple[0] = V1.X;
		tuple[1] = V1.Y;
		tuple[2] = V1.Z;
		tuple[3] = V2.X;		
		tuple[4] = V2.Y;
		tuple[5] = V2.Z;
		tuple[6] = V3.X;
		tuple[7] = V3.Y;
		tuple[8] = V3.Z;		
	    }
	}

	// create a diagonal matrix
	public Matrix3f(float M00, float M11, float M22) {
	    tuple = new float[9];

	    MakeDiagonal(M00, M11, M22);
	}

	// create a rotation matrix (positive angle - counterclockwise)
	public Matrix3f(Vector3f Axis, float Angle) {
	    tuple = new float[9];

	    FromAxisAngle(Axis, Angle);
	}

	public void MakeZero() {
	    tuple[0] = 0.0f;
	    tuple[1] = 0.0f;
	    tuple[2] = 0.0f;
	    tuple[3] = 0.0f;
	    tuple[4] = 0.0f;
	    tuple[5] = 0.0f;
	    tuple[6] = 0.0f;
	    tuple[7] = 0.0f;
	    tuple[8] = 0.0f;
	}

	public void MakeIdentity() {
	    tuple[0] = 1.0f;
	    tuple[1] = 0.0f;
	    tuple[2] = 0.0f;
	    tuple[3] = 0.0f;
	    tuple[4] = 1.0f;
	    tuple[5] = 0.0f;
	    tuple[6] = 0.0f;
	    tuple[7] = 0.0f;
	    tuple[8] = 1.0f;
	}

	public void MakeDiagonal(float M00, float M11, float M22) {
	    tuple[0] = M00;
	    tuple[1] = 0.0f;
	    tuple[2] = 0.0f;
	    tuple[3] = 0.0f;
	    tuple[4] = M11;
	    tuple[5] = 0.0f;
	    tuple[6] = 0.0f;
	    tuple[7] = 0.0f;
	    tuple[8] = M22;
	}

	public void FromAxisAngle(Vector3f Axis, float Angle) {
	    float Cos = (float)System.Math.Cos(Angle);
	    float Sin = (float)System.Math.Sin(Angle);
	    float OneMinusCos = 1.0f - Cos;
	    float X2 = Axis.X * Axis.X;
	    float Y2 = Axis.Y * Axis.Y;
	    float Z2 = Axis.Z * Axis.Z;
	    float XYM = Axis.X * Axis.Y * OneMinusCos;
	    float XZM = Axis.X * Axis.Z * OneMinusCos;
	    float YZM = Axis.Y * Axis.Z * OneMinusCos;
	    float XSin = Axis.X * Sin;
	    float YSin = Axis.Y * Sin;
	    float ZSin = Axis.Z * Sin;

	    tuple[0] = X2 * OneMinusCos + Cos;
	    tuple[1] = XYM - ZSin;
	    tuple[2] = XZM + YSin;
	    tuple[3] = XYM + ZSin;
	    tuple[4] = Y2 * OneMinusCos + Cos;
	    tuple[5] = YZM - XSin;
	    tuple[6] = XZM - YSin;
	    tuple[7] = YZM + XSin;
	    tuple[8] = Z2 * OneMinusCos + Cos;
	}

       // accessors
	public float[] Matrix3 {
	    get {
		return tuple;
	    }

	    set {
		tuple = value;
	    }
	}

	public float Get(short Column, short Row) {
	    return tuple[Column + 3 * Row];
	}

	public void Set(float Value, short Column, short Row) {
	    tuple[Column + 3 * Row] = Value;
	}

	public Vector3f GetRow(short Row) {
	    int i0 = 3*Row;
	    return new Vector3f(tuple[i0], tuple[i0+1], tuple[i0+2]);
	}

	public void SetRow(short Row, Vector3f V) {
	    int i0 = 3*Row;
	    tuple[i0] = V.X;
	    tuple[i0+1] = V.Y;
	    tuple[i0+2] = V.Z;
	}

	// comparison
	public static bool operator==(Matrix3f M1, Matrix3f M2) {
	    return M1.tuple == M2.tuple;
	}

	public static bool operator!=(Matrix3f M1, Matrix3f M2) {
	    return M1.tuple != M2.tuple;
	}

	public static bool operator<(Matrix3f M1, Matrix3f M2) {
	    return (M1.tuple[0] < M2.tuple[0] &&
		    M1.tuple[1] < M2.tuple[1] &&
		    M1.tuple[2] < M2.tuple[2] &&
		    M1.tuple[3] < M2.tuple[3] &&
		    M1.tuple[4] < M2.tuple[4] &&
		    M1.tuple[5] < M2.tuple[5] &&
		    M1.tuple[6] < M2.tuple[6] &&
		    M1.tuple[7] < M2.tuple[7] &&
		    M1.tuple[8] < M2.tuple[8]);
	}

	public static bool operator>(Matrix3f M1, Matrix3f M2) {
	    return (M1.tuple[0] > M2.tuple[0] &&
		    M1.tuple[1] > M2.tuple[1] &&
		    M1.tuple[2] > M2.tuple[2] &&
		    M1.tuple[3] > M2.tuple[3] &&
		    M1.tuple[4] > M2.tuple[4] &&
		    M1.tuple[5] > M2.tuple[5] &&
		    M1.tuple[6] > M2.tuple[6] &&
		    M1.tuple[7] > M2.tuple[7] &&
		    M1.tuple[8] > M2.tuple[8]);
	}

	public static bool operator<=(Matrix3f M1, Matrix3f M2) {
	    return (M1.tuple[0] <= M2.tuple[0] &&
		    M1.tuple[1] <= M2.tuple[1] &&
		    M1.tuple[2] <= M2.tuple[2] &&
		    M1.tuple[3] <= M2.tuple[3] &&
		    M1.tuple[4] <= M2.tuple[4] &&
		    M1.tuple[5] <= M2.tuple[5] &&
		    M1.tuple[6] <= M2.tuple[6] &&
		    M1.tuple[7] <= M2.tuple[7] &&
		    M1.tuple[8] <= M2.tuple[8]);
	}

	public static bool operator>=(Matrix3f M1, Matrix3f M2) {
	    return (M1.tuple[0] >= M2.tuple[0] &&
		    M1.tuple[1] >= M2.tuple[1] &&
		    M1.tuple[2] >= M2.tuple[2] &&
		    M1.tuple[3] >= M2.tuple[3] &&
		    M1.tuple[4] >= M2.tuple[4] &&
		    M1.tuple[5] >= M2.tuple[5] &&
		    M1.tuple[6] >= M2.tuple[6] &&
		    M1.tuple[7] >= M2.tuple[7] &&
		    M1.tuple[8] >= M2.tuple[8]);
	}

	public override bool Equals(object value) {
	    if(value == null) return false;
	    if (GetType() == value.GetType()) return this == (Matrix3f)value;
	    
	    return false;
	}

	public override int GetHashCode() {
	    return tuple.GetHashCode();
	}

	// operators
	public static Matrix3f operator+(Matrix3f M1, Matrix3f M2) {
	    return new Matrix3f(M1.tuple[0] + M2.tuple[0],
				M1.tuple[1] + M2.tuple[1],
				M1.tuple[2] + M2.tuple[2],
				M1.tuple[3] + M2.tuple[3],
				M1.tuple[4] + M2.tuple[4],
				M1.tuple[5] + M2.tuple[5],
				M1.tuple[6] + M2.tuple[6],
				M1.tuple[7] + M2.tuple[7],
				M1.tuple[8] + M2.tuple[8]);
	}

	public static Matrix3f operator-(Matrix3f M1, Matrix3f M2) {
	    return new Matrix3f(M1.tuple[0] - M2.tuple[0],
				M1.tuple[1] - M2.tuple[1],
				M1.tuple[2] - M2.tuple[2],
				M1.tuple[3] - M2.tuple[3],
				M1.tuple[4] - M2.tuple[4],
				M1.tuple[5] - M2.tuple[5],
				M1.tuple[6] - M2.tuple[6],
				M1.tuple[7] - M2.tuple[7],
				M1.tuple[8] - M2.tuple[8]);
	}

	public static Matrix3f operator*(Matrix3f M1, Matrix3f M2) {
	    return new Matrix3f(M1.tuple[0] * M2.tuple[0] + M1.tuple[1] * M2.tuple[3] + M1.tuple[2] * M2.tuple[6],
				M1.tuple[0] * M2.tuple[1] + M1.tuple[1] * M2.tuple[4] + M1.tuple[2] * M2.tuple[7],
				M1.tuple[0] * M2.tuple[2] + M1.tuple[1] * M2.tuple[5] + M1.tuple[2] * M2.tuple[8],
				M1.tuple[3] * M2.tuple[0] + M1.tuple[4] * M2.tuple[3] + M1.tuple[6] * M2.tuple[6],
				M1.tuple[3] * M2.tuple[1] + M1.tuple[4] * M2.tuple[4] + M1.tuple[5] * M2.tuple[7],
				M1.tuple[3] * M2.tuple[2] + M1.tuple[4] * M2.tuple[5] + M1.tuple[5] * M2.tuple[8],
				M1.tuple[6] * M2.tuple[0] + M1.tuple[7] * M2.tuple[3] + M1.tuple[8] * M2.tuple[6],
				M1.tuple[6] * M2.tuple[1] + M1.tuple[7] * M2.tuple[4] + M1.tuple[8] * M2.tuple[7],
				M1.tuple[6] * M2.tuple[2] + M1.tuple[7] * M2.tuple[5] + M1.tuple[8] * M2.tuple[8]);
	}

	public static Matrix3f operator*(Matrix3f M, float Scalar) {
	    return new Matrix3f(M.tuple[0] * Scalar,
				M.tuple[1] * Scalar,
				M.tuple[2] * Scalar,
				M.tuple[3] * Scalar,
				M.tuple[4] * Scalar,
				M.tuple[5] * Scalar,
				M.tuple[6] * Scalar,
				M.tuple[7] * Scalar,
				M.tuple[8] * Scalar);
	}

	public static Matrix3f operator/(Matrix3f M, float Scalar) {
	    if(Scalar != 0.0f) {
		float reciproke = 1.0f/Scalar;

		return new Matrix3f(M.tuple[0] * reciproke,
				    M.tuple[1] * reciproke,
				    M.tuple[2] * reciproke,
				    M.tuple[3] * reciproke,
				    M.tuple[4] * reciproke,
				    M.tuple[5] * reciproke,
				    M.tuple[6] * reciproke,
				    M.tuple[7] * reciproke,
				    M.tuple[8] * reciproke);
	    }
	    else {
		return new Matrix3f(float.MaxValue,
				    float.MaxValue,
				    float.MaxValue,
				    float.MaxValue,
				    float.MaxValue,
				    float.MaxValue,
				    float.MaxValue,
				    float.MaxValue,
				    float.MaxValue);
	    }
	}

	public static Vector3f operator*(Matrix3f M, Vector3f V) {
	    return new Vector3f(M.tuple[0] * V.X + M.tuple[1] * V.Y + M.tuple[2] * V.Z,
				M.tuple[3] * V.X + M.tuple[4] * V.Y + M.tuple[5] * V.Z,
				M.tuple[6] * V.X + M.tuple[7] * V.Y + M.tuple[8] * V.Z);
	}

	public static Matrix3f operator-(Matrix3f M) {
	    return new Matrix3f(-M.tuple[0],
				-M.tuple[1],
				-M.tuple[2],
				-M.tuple[3],
				-M.tuple[4],
				-M.tuple[5],
				-M.tuple[6],
				-M.tuple[7],
				-M.tuple[8]);
	}

	public Matrix3f Transpose() {
	    return new Matrix3f(tuple[0],
				tuple[3],
				tuple[6],
				tuple[1],
				tuple[4],
				tuple[7],
				tuple[2],
				tuple[5],
				tuple[8]);
	}

	private float[] tuple;
    }

    public class Matrix3d {

	// Constructors

        // create identity matrix
	public Matrix3d() {
	    tuple = new double[9];
	    MakeIdentity();
	}

	// copy constructor
	public Matrix3d(Matrix3d M) {
	    tuple = new double[9];
	    tuple[0] = M.tuple[0];
	    tuple[1] = M.tuple[1];
	    tuple[2] = M.tuple[2];
	    tuple[3] = M.tuple[3];
	    tuple[4] = M.tuple[4];
	    tuple[5] = M.tuple[5];
	    tuple[6] = M.tuple[6];
	    tuple[7] = M.tuple[7];
	    tuple[8] = M.tuple[8];
	}

	// construct from doubleing points
	public Matrix3d(double M00, double M01, double M02, double M10, double M11, double M12, double M20, double M21, double M22) {
	    tuple = new double[9];
	    tuple[0] = M00;
	    tuple[1] = M01;
	    tuple[2] = M02;
	    tuple[3] = M10;
	    tuple[4] = M11;
	    tuple[5] = M12;
	    tuple[6] = M20;
	    tuple[7] = M21;
	    tuple[8] = M22;
	}

	// construct from vectors
	// colums means:
	// true: vectors are colums of the matrix
	// false: vectors are rows of the matrix
	public Matrix3d(Vector3d V1, Vector3d V2, Vector3d V3, bool colums) {
	    tuple = new double[9];
	    if(colums) {
		tuple[0] = V1.X;
		tuple[1] = V2.X;
		tuple[2] = V3.X;
		tuple[3] = V1.Y;
		tuple[4] = V2.Y;
		tuple[5] = V3.Y;
		tuple[6] = V1.Z;
		tuple[7] = V2.Z;
		tuple[8] = V3.Z;		
	    }
	    else {
		tuple[0] = V1.X;
		tuple[1] = V1.Y;
		tuple[2] = V1.Z;
		tuple[3] = V2.X;		
		tuple[4] = V2.Y;
		tuple[5] = V2.Z;
		tuple[6] = V3.X;
		tuple[7] = V3.Y;
		tuple[8] = V3.Z;		
	    }
	}

	// create a diagonal matrix
	public Matrix3d(double M00, double M11, double M22) {
	    tuple = new double[9];

	    MakeDiagonal(M00, M11, M22);
	}

	// create a rotation matrix (positive angle - counterclockwise)
	public Matrix3d(Vector3d Axis, double Angle) {
	    tuple = new double[9];

	    FromAxisAngle(Axis, Angle);
	}

	public void MakeZero() {
	    tuple[0] = 0.0;
	    tuple[1] = 0.0;
	    tuple[2] = 0.0;
	    tuple[3] = 0.0;
	    tuple[4] = 0.0;
	    tuple[5] = 0.0;
	    tuple[6] = 0.0;
	    tuple[7] = 0.0;
	    tuple[8] = 0.0;
	}

	public void MakeIdentity() {
	    tuple[0] = 1.0;
	    tuple[1] = 0.0;
	    tuple[2] = 0.0;
	    tuple[3] = 0.0;
	    tuple[4] = 1.0;
	    tuple[5] = 0.0;
	    tuple[6] = 0.0;
	    tuple[7] = 0.0;
	    tuple[8] = 1.0;
	}

	public void MakeDiagonal(double M00, double M11, double M22) {
	    tuple[0] = M00;
	    tuple[1] = 0.0;
	    tuple[2] = 0.0;
	    tuple[3] = 0.0;
	    tuple[4] = M11;
	    tuple[5] = 0.0;
	    tuple[6] = 0.0;
	    tuple[7] = 0.0;
	    tuple[8] = M22;
	}

	public void FromAxisAngle(Vector3d Axis, double Angle) {
	    double Cos = (double)System.Math.Cos(Angle);
	    double Sin = (double)System.Math.Sin(Angle);
	    double OneMinusCos = 1.0f - Cos;
	    double X2 = Axis.X * Axis.X;
	    double Y2 = Axis.Y * Axis.Y;
	    double Z2 = Axis.Z * Axis.Z;
	    double XYM = Axis.X * Axis.Y * OneMinusCos;
	    double XZM = Axis.X * Axis.Z * OneMinusCos;
	    double YZM = Axis.Y * Axis.Z * OneMinusCos;
	    double XSin = Axis.X * Sin;
	    double YSin = Axis.Y * Sin;
	    double ZSin = Axis.Z * Sin;

	    tuple[0] = X2 * OneMinusCos + Cos;
	    tuple[1] = XYM - ZSin;
	    tuple[2] = XZM + YSin;
	    tuple[3] = XYM + ZSin;
	    tuple[4] = Y2 * OneMinusCos + Cos;
	    tuple[5] = YZM - XSin;
	    tuple[6] = XZM - YSin;
	    tuple[7] = YZM + XSin;
	    tuple[8] = Z2 * OneMinusCos + Cos;
	}

       // accessors
	public double[] Matrix3 {
	    get {
		return tuple;
	    }

	    set {
		tuple = value;
	    }
	}

	public double Get(short Column, short Row) {
	    return tuple[Column + 3 * Row];
	}

	public void Set(double Value, short Column, short Row) {
	    tuple[Column + 3 * Row] = Value;
	}

	public Vector3d GetRow(short Row) {
	    int i0 = 3*Row;
	    return new Vector3d(tuple[i0], tuple[i0+1], tuple[i0+2]);
	}

	public void SetRow(short Row, Vector3d V) {
	    int i0 = 3*Row;
	    tuple[i0] = V.X;
	    tuple[i0+1] = V.Y;
	    tuple[i0+2] = V.Z;
	}

	// comparison
	public static bool operator==(Matrix3d M1, Matrix3d M2) {
	    return M1.tuple == M2.tuple;
	}

	public static bool operator!=(Matrix3d M1, Matrix3d M2) {
	    return M1.tuple != M2.tuple;
	}

	public static bool operator<(Matrix3d M1, Matrix3d M2) {
	    return (M1.tuple[0] < M2.tuple[0] &&
		    M1.tuple[1] < M2.tuple[1] &&
		    M1.tuple[2] < M2.tuple[2] &&
		    M1.tuple[3] < M2.tuple[3] &&
		    M1.tuple[4] < M2.tuple[4] &&
		    M1.tuple[5] < M2.tuple[5] &&
		    M1.tuple[6] < M2.tuple[6] &&
		    M1.tuple[7] < M2.tuple[7] &&
		    M1.tuple[8] < M2.tuple[8]);
	}

	public static bool operator>(Matrix3d M1, Matrix3d M2) {
	    return (M1.tuple[0] > M2.tuple[0] &&
		    M1.tuple[1] > M2.tuple[1] &&
		    M1.tuple[2] > M2.tuple[2] &&
		    M1.tuple[3] > M2.tuple[3] &&
		    M1.tuple[4] > M2.tuple[4] &&
		    M1.tuple[5] > M2.tuple[5] &&
		    M1.tuple[6] > M2.tuple[6] &&
		    M1.tuple[7] > M2.tuple[7] &&
		    M1.tuple[8] > M2.tuple[8]);
	}

	public static bool operator<=(Matrix3d M1, Matrix3d M2) {
	    return (M1.tuple[0] <= M2.tuple[0] &&
		    M1.tuple[1] <= M2.tuple[1] &&
		    M1.tuple[2] <= M2.tuple[2] &&
		    M1.tuple[3] <= M2.tuple[3] &&
		    M1.tuple[4] <= M2.tuple[4] &&
		    M1.tuple[5] <= M2.tuple[5] &&
		    M1.tuple[6] <= M2.tuple[6] &&
		    M1.tuple[7] <= M2.tuple[7] &&
		    M1.tuple[8] <= M2.tuple[8]);
	}

	public static bool operator>=(Matrix3d M1, Matrix3d M2) {
	    return (M1.tuple[0] >= M2.tuple[0] &&
		    M1.tuple[1] >= M2.tuple[1] &&
		    M1.tuple[2] >= M2.tuple[2] &&
		    M1.tuple[3] >= M2.tuple[3] &&
		    M1.tuple[4] >= M2.tuple[4] &&
		    M1.tuple[5] >= M2.tuple[5] &&
		    M1.tuple[6] >= M2.tuple[6] &&
		    M1.tuple[7] >= M2.tuple[7] &&
		    M1.tuple[8] >= M2.tuple[8]);
	}

	public override bool Equals(object value) {
	    if(value == null) return false;
	    if (GetType() == value.GetType()) return this == (Matrix3d)value;
	    
	    return false;
	}

	public override int GetHashCode() {
	    return tuple.GetHashCode();
	}

	// operators
	public static Matrix3d operator+(Matrix3d M1, Matrix3d M2) {
	    return new Matrix3d(M1.tuple[0] + M2.tuple[0],
				M1.tuple[1] + M2.tuple[1],
				M1.tuple[2] + M2.tuple[2],
				M1.tuple[3] + M2.tuple[3],
				M1.tuple[4] + M2.tuple[4],
				M1.tuple[5] + M2.tuple[5],
				M1.tuple[6] + M2.tuple[6],
				M1.tuple[7] + M2.tuple[7],
				M1.tuple[8] + M2.tuple[8]);
	}

	public static Matrix3d operator-(Matrix3d M1, Matrix3d M2) {
	    return new Matrix3d(M1.tuple[0] - M2.tuple[0],
				M1.tuple[1] - M2.tuple[1],
				M1.tuple[2] - M2.tuple[2],
				M1.tuple[3] - M2.tuple[3],
				M1.tuple[4] - M2.tuple[4],
				M1.tuple[5] - M2.tuple[5],
				M1.tuple[6] - M2.tuple[6],
				M1.tuple[7] - M2.tuple[7],
				M1.tuple[8] - M2.tuple[8]);
	}

	public static Matrix3d operator*(Matrix3d M1, Matrix3d M2) {
	    return new Matrix3d(M1.tuple[0] * M2.tuple[0] + M1.tuple[1] * M2.tuple[3] + M1.tuple[2] * M2.tuple[6],
				M1.tuple[0] * M2.tuple[1] + M1.tuple[1] * M2.tuple[4] + M1.tuple[2] * M2.tuple[7],
				M1.tuple[0] * M2.tuple[2] + M1.tuple[1] * M2.tuple[5] + M1.tuple[2] * M2.tuple[8],
				M1.tuple[3] * M2.tuple[0] + M1.tuple[4] * M2.tuple[3] + M1.tuple[6] * M2.tuple[6],
				M1.tuple[3] * M2.tuple[1] + M1.tuple[4] * M2.tuple[4] + M1.tuple[5] * M2.tuple[7],
				M1.tuple[3] * M2.tuple[2] + M1.tuple[4] * M2.tuple[5] + M1.tuple[5] * M2.tuple[8],
				M1.tuple[6] * M2.tuple[0] + M1.tuple[7] * M2.tuple[3] + M1.tuple[8] * M2.tuple[6],
				M1.tuple[6] * M2.tuple[1] + M1.tuple[7] * M2.tuple[4] + M1.tuple[8] * M2.tuple[7],
				M1.tuple[6] * M2.tuple[2] + M1.tuple[7] * M2.tuple[5] + M1.tuple[8] * M2.tuple[8]);
	}

	public static Matrix3d operator*(Matrix3d M, double Scalar) {
	    return new Matrix3d(M.tuple[0] * Scalar,
				M.tuple[1] * Scalar,
				M.tuple[2] * Scalar,
				M.tuple[3] * Scalar,
				M.tuple[4] * Scalar,
				M.tuple[5] * Scalar,
				M.tuple[6] * Scalar,
				M.tuple[7] * Scalar,
				M.tuple[8] * Scalar);
	}

	public static Matrix3d operator/(Matrix3d M, double Scalar) {
	    if(Scalar != 0.0) {
		double reciproke = 1.0/Scalar;

		return new Matrix3d(M.tuple[0] * reciproke,
				    M.tuple[1] * reciproke,
				    M.tuple[2] * reciproke,
				    M.tuple[3] * reciproke,
				    M.tuple[4] * reciproke,
				    M.tuple[5] * reciproke,
				    M.tuple[6] * reciproke,
				    M.tuple[7] * reciproke,
				    M.tuple[8] * reciproke);
	    }
	    else {
		return new Matrix3d(double.MaxValue,
				    double.MaxValue,
				    double.MaxValue,
				    double.MaxValue,
				    double.MaxValue,
				    double.MaxValue,
				    double.MaxValue,
				    double.MaxValue,
				    double.MaxValue);
	    }
	}

	public static Vector3d operator*(Matrix3d M, Vector3d V) {
	    return new Vector3d(M.tuple[0] * V.X + M.tuple[1] * V.Y + M.tuple[2] * V.Z,
				M.tuple[3] * V.X + M.tuple[4] * V.Y + M.tuple[5] * V.Z,
				M.tuple[6] * V.X + M.tuple[7] * V.Y + M.tuple[8] * V.Z);
	}

	public static Matrix3d operator-(Matrix3d M) {
	    return new Matrix3d(-M.tuple[0],
				-M.tuple[1],
				-M.tuple[2],
				-M.tuple[3],
				-M.tuple[4],
				-M.tuple[5],
				-M.tuple[6],
				-M.tuple[7],
				-M.tuple[8]);
	}

	public Matrix3d Transpose() {
	    return new Matrix3d(tuple[0],
				tuple[3],
				tuple[6],
				tuple[1],
				tuple[4],
				tuple[7],
				tuple[2],
				tuple[5],
				tuple[8]);
	}

	private double[] tuple;
    }

}
